package com.lxl.message;

import com.alibaba.fastjson.JSON;
import com.lxl.config.SystemConfig;
import com.lxl.config.ServiceFunction;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.lxl.message.TemplateStringUtils.*;

/*
* Kettle传递过来的数据以行为单位，
* 所以转化实际上是对行的数据进行映射
* 001506716
* 001507069
* */
public class TemplateParser {

    public static void main(String[] args) throws Exception {
        System.out.println("Start : " + new SimpleDateFormat("HHmmssSSS").format(new Date()));

        TemplateMeta tm = buildTemplateMeta(FileUtils.readFileToString(new File(SystemConfig.SERVER_CONFIG_PATH + "x.template")));
        String msgContent = FileUtils.readFileToString(new File(SystemConfig.SERVER_CONFIG_PATH + "data.xml"));
        TemplateData td = buildTemplateData(MsgStatus.SUCCESS, msgContent, tm);
        parse(td, tm.structure, 0, td.arrayLength);
        System.out.println(buildResult(td, tm, "xml"));
        System.out.println("End : " + new SimpleDateFormat("HHmmssSSS").format(new Date()));
    }

    public static void toXmlString(List<Map> source, Element father, Element son){
        boolean isNested = true;
        if (son == null) {
            son = father;
            isNested = false;
        }

        for (int i=0; i<source.size(); i++) {
            Map<String, Object> temp = source.get(i);
            for (Map.Entry<String, Object> entry : temp.entrySet()) {
                if (entry.getValue() instanceof String) {
                    Element element = DocumentHelper.createElement(entry.getKey());
                    element.addText(entry.getValue()+"");
                    son.add(element);
                } else if (entry.getValue() instanceof  List) {
                    if (entry.getKey().contains(".")){
                        String[] keys = entry.getKey().split("\\.");
                        List<Element> keyEles = new LinkedList<>();
                        for (String key : keys){
                            Element element = DocumentHelper.createElement(key);
                            keyEles.add(element);
                        }
                        toXmlString((List<Map>) entry.getValue(), keyEles.get(0), keyEles.get(keyEles.size()-1));
                        son.add(keyEles.get(0));
                    } else {
                        Element ele = DocumentHelper.createElement(entry.getKey());
                        toXmlString((List<Map>) entry.getValue(), ele, null);

                        son.add(ele);
                    }
                }
            }
            if (isNested){
                Element ele = (Element) son.clone();
                father.add(ele);
                son.clearContent();
            }
        }
    }

    //模板解析为对象
    public static TemplateMeta[] buildTemplateMetaList(String templateStr){
        TemplateMeta[] tdmLists = new TemplateMeta[2];
        String[] templateBlock = templateStr.split("@");
        TemplateMeta tdm1,tdm2;
        if (templateBlock.length >= 2){
            tdm1 = buildTemplateMeta(templateBlock[0]);
            tdm2 = buildTemplateMeta(templateBlock[1]);
        }else if (templateBlock.length == 1){
            tdm1 = buildTemplateMeta(templateBlock[0]);
            tdm2 = null;
        }else{
            tdm1 = null;
            tdm2 = null;
        }

        if (tdm1!=null){
            if ("json".equals(tdm1.type)){
                tdmLists[0] = tdm1;
                tdmLists[1] = tdm2;
            } else {
                tdmLists[0] = tdm2;
                tdmLists[1] = tdm1;
            }
        }

        return tdmLists;
    }
    //将模板文件抽象为模板类对象
    public static TemplateMeta buildTemplateMeta(String tempalteStr){
        return new TemplateMeta(tempalteStr);
    }
    //根据模板文件和数据内容构建数据矩阵
    public static TemplateData buildTemplateData(MsgStatus status, String msgContent, TemplateMeta templateMeta){
        return new TemplateData(status, msgContent, templateMeta);
    }

    public static void parse(TemplateData data, TemplateStructure structure,int start,int end){
        parse(data, structure, start, end, data.dataMapTree);
    }

    private static void parse(TemplateData data, TemplateStructure structure,int start,int end, List<Map> result){
        List<Integer> limits;//分割层
        int groupLength = 0;//分组个数

        if (structure.hasObject()){
            List<String> keys = new LinkedList<>();
            for (Map.Entry<String, String> entry : structure.getObject().entrySet()){
                if (isKeyTag(entry.getKey())){
                    keys.add(entry.getKey());
                }
            }

            limits = getBoundary(keys, data.dataMatrix, start, end);
            groupLength = limits.size()-1;

            //每层界限进行循环
            for (int i=0; i<groupLength; i++){
                Map<String, Object> iResult = new LinkedHashMap<>();
//                String keyStr = "";
                for (Map.Entry<String, String> entry : structure.getObject().entrySet()){
                    if (isKeyTag(entry.getKey()))
//                        keyStr = keyStr + "[" + ((List<String>)data.dataMatrix.get(entry.getKey())).get(limits.get(i)) + "]";
                        iResult.put(getBracketedStr(entry.getKey()), ((List<String>)data.dataMatrix.get(entry.getKey())).get(limits.get(i)));
                    else if (isSysTag(entry.getKey()))
//                        keyStr = keyStr + "[-" + data.dataMatrix.get(entry.getKey()) + "-]";
                        iResult.put(getBracketedStr(entry.getKey()), data.dataMatrix.get(entry.getKey()));
                }
//                System.out.println(keyStr);

                if (structure.hasArray()){
                    for (Map.Entry<String, TemplateStructure> entry : structure.getArray().entrySet()){
                        List<Map> temp = new LinkedList<>();
                        parse(data, entry.getValue(), limits.get(i), limits.get(i+1), temp);
                        if (temp.size()>0)
                            iResult.put(getBracketedStr(entry.getKey()),temp);
                    }
                }

                if (iResult.size()>0)
                    result.add(iResult);
            }

            //若object中都是系统功能，并没有key
            if (groupLength<=0){
                Map<String, Object> iResult = new LinkedHashMap<>();
//                String keyStr = "";
                for (Map.Entry<String, String> entry : structure.getObject().entrySet()){
                    assert (isSysTag(entry.getKey()));
//                    keyStr = keyStr + "[-" + data.dataMatrix.get(entry.getKey()) + "-]";
                    iResult.put(getBracketedStr(entry.getKey()), data.dataMatrix.get(entry.getKey()));
                }

                if (structure.hasArray()){
                    for (Map.Entry<String, TemplateStructure> entry : structure.getArray().entrySet()){
                        List<Map> temp = new LinkedList<>();
                        parse(data, entry.getValue(), start, end, temp);
                        if (temp.size()>0)
                            iResult.put(getBracketedStr(entry.getKey()), temp);
                    }
                }

                if (iResult.size()>0)
                    result.add(iResult);
            }
        } else if (structure.hasArray()){
            Map<String, Object> iResult = new LinkedHashMap<>();
            for (Map.Entry<String, TemplateStructure> entry : structure.getArray().entrySet()){
                List<Map> temp = new LinkedList<>();
                parse(data, entry.getValue(), start, end, temp);
                if (temp.size()>0)
                    iResult.put(getBracketedStr(entry.getKey()), temp);
            }
            if (iResult.size()>0)
                result.add(iResult);
        }
    }

    private static List<Integer> getBoundary(List<String> keys, Map<String, Object> matrix, int start, int end){
        List<Integer> index = new LinkedList<>();//存放边界的位置
        if (keys.size() > 0){
            Set<List<String>> limitSets = new HashSet<>();//使用HashSet比较多元组的异同
            for (int i=start; i<end; i++){
                List<String> temp = new LinkedList<>();
                for (String key : keys){
                    assert (isKeyTag(key));
                    System.out.println(key);
                    temp.add(((List<String>)matrix.get(key)).get(i));
                }

                if (!limitSets.contains(temp)){
                    index.add(i);
                    limitSets.add(temp);
                }
            }
            index.add(end);
        }

        return index;
    }

    //根据结构返回相应的格式
    public static String buildResult(TemplateData data, TemplateMeta meta , String type){
        if ("xml".equals(type)){
            Element father = DocumentHelper.createElement("FUNSO-HEADER");
            toXmlString(data.dataMapTree, father, null);
            Document document = DocumentHelper.createDocument();
            if(father.elements().size()==1){
                document.setRootElement((Element) father.elements().get(0));
            } else {
                document.setRootElement(father);
            }
            document.setXMLEncoding(meta.encoding);
            return  document.asXML();
        } else {//默认采用json格式返回
            return JSON.toJSONString(data.dataMapTree);
        }
    }

    @Deprecated
    private static String assignServiceFunction(String content){
        Pattern pattern = Pattern.compile("#\\w+#");
        Matcher matcher = pattern.matcher(content);
        while(matcher.find()){
            String serviceFunName = StringUtils.strip(matcher.group(), "#");
            content = content.replaceAll(matcher.group(), ServiceFunction.valueOf(serviceFunName).getFunc()+"");
        }

        return content;
    }

    private static void traverseNestedMap(Map<String, Object> nestedMap){
        for (Map.Entry<String, Object> entry : nestedMap.entrySet()){
            if (entry.getValue() instanceof List){
                System.out.println("In key-value.size: [" + entry.getKey() + "-" + ((List) entry.getValue()).size() + "]");
            } else if (entry.getValue() instanceof Map){
                System.out.println("In key: " + entry.getKey());
                traverseNestedMap((Map<String, Object>)entry.getValue());
                System.out.println("Out key: " + entry.getKey());
            } else if (entry.getValue() instanceof  String){
                System.out.println("In key-value: [" + entry.getKey() + "-" + entry.getValue() + "]");
            }
        }
    }

    private static void traverseNestedMapList(List<Map> nested){
        for (int i=0; i<nested.size(); i++){
            Map<String, Object> temp = nested.get(i);
            for (Map.Entry<String, Object> entry : temp.entrySet()){
                if (entry.getValue() instanceof  List){
                    System.out.println("In array :" + entry.getKey());
                    traverseNestedMapList((List<Map>) entry.getValue());
                    System.out.println("Out array : " + entry.getKey());
                } else if (entry.getValue() instanceof String){
                    System.out.println("In key-value "+ "{" + i + "}" +": [" + entry.getKey() + "," + entry.getValue() + "]");
                }
            }
        }
    }
}